import { EmitType, Fn } from "/#/index";
import { Recordable } from "/#/global";
import type {
  FilterMethods,
  Filters,
  TableColumnCtx as ColumnProps,
} from "element-plus/lib/components/table/src/table-column/defaults";
import { FormProps } from "../../../Form/src/types/form";
import { VueNode } from "@/utils/propTypes";
import { ComponentType } from "./componentType";
import { RoleEnum } from "@/enums/roleEnum";
import { VNode, VNodeChild } from "vue";
import { PaginationProps } from "./pagination";
import { TableProps } from "element-plus/es/components/table/src/table/defaults";

export declare type SortOrder = "ascending" | "descending";
export type SizeType = "default" | "small" | "large";

export interface FetchParams {
  searchInfo?: Recordable;
  page?: number;
  sortInfo?: Recordable;
  filterInfo?: Recordable;
}

export interface SorterResult {
  column: ColumnProps<any>;
  order: SortOrder;
  field: string;
  columnKey: string;
}

export interface TableSetting {
  // 刷新
  redo?: boolean;
  // 大小
  size?: boolean;
  // 设置
  setting?: boolean;
  // 全屏
  fullScreen?: boolean;
}

export interface FetchSetting {
  // 请求接口当前页数
  pageField: string;
  // 每页显示多少条
  sizeField: string;
  // 请求结果列表字段  支持 a.b.c
  listField: string;
  // 请求结果总数字段  支持 a.b.c
  totalField: string;
}

export type CellFormat =
  | string
  | ((text: string, record: Recordable, index: number) => string | number)
  | Map<string | number, any>;

declare type CI<T> = {
  column: BasicColumn<T>;
  $index: number;
};
// @ts-ignore
export interface BasicColumn<T> extends ColumnProps<T> {
  id?: string;
  realWidth?: number;
  type?: "index" | "DEFAULT" | "CHECKBOX" | "RADIO" | "ACTION" | undefined;
  label?: string;
  className?: string;
  labelClassName?: string;
  property?: string;
  prop?: string;
  width?: string | number;
  minWidth?: string | number;
  renderHeader?: (data: CI<T>) => VNode;
  sortable?: boolean | string;
  sortMethod?: (a: T, b: T) => number;
  sortBy?: string | ((row: T, index: number) => string) | string[];
  resizable?: boolean;
  columnKey?: string | number;
  rawColumnKey?: string;
  align?: string;
  headerAlign?: string;
  showTooltipWhenOverflow?: boolean;
  showOverflowTooltip?: boolean;
  fixed?: boolean | string;
  formatter?: (
    row: T,
    column: BasicColumn<Recordable>,
    cellValue: any,
    index: number
  ) => VNode | string;
  selectable?: (row: T, index: number) => boolean;
  reserveSelection?: boolean;
  filterMethod?: FilterMethods<any>;
  filteredValue?: string[];
  filterPlacement?: string;
  filterMultiple?: boolean;
  index?: string | number;
  sortOrders?: ("ascending" | "descending" | null)[];
  renderCell?: (data: any) => void;
  colSpan?: number;
  rowSpan?: number;
  level?: number;
  filterable?: boolean | FilterMethods<any> | Filters;
  order?: string;
  isColumnGroup?: boolean;
  isSubColumn?: boolean;
  columns?: BasicColumn<Recordable>[];
  getColumnIndex?: () => number;
  no?: number;
  children?: BasicColumn<Recordable>[];
  filters?: {
    text: string;
    value: string;
    children?:
      | unknown[]
      | (((props: Record<string, unknown>) => unknown[]) &
          (() => unknown[]) &
          (() => unknown[]));
  }[];
  customTitle?: VueNode;

  slots?: Recordable;

  // Whether to hide the column by default, it can be displayed in the column configuration
  defaultHidden?: boolean;

  // Help text for table column header
  helpMessage?: string | string[];

  format?: CellFormat;

  // Editable
  edit?: boolean;
  editRow?: boolean;
  editable?: boolean;
  editComponent?: ComponentType;
  editComponentProps?:
    | ((opt: {
        text: string | number | boolean | Recordable;
        record: Recordable;
        column: BasicColumn<Recordable>;
        index: number;
      }) => Recordable)
    | Recordable;
  editRule?: boolean | ((text: string, record: Recordable) => Promise<string>);
  editValueMap?: (value: any) => string;
  onEditRow?: () => void;
  // 权限编码控制是否显示
  auth?: RoleEnum | RoleEnum[] | string | string[];
  // 业务控制是否显示
  ifShow?: boolean | ((column: BasicColumn<Recordable>) => boolean);
  // 自定义修改后显示的内容
  editRender?: (opt: {
    text: string | number | boolean | Recordable;
    record: Recordable;
    column: BasicColumn<Recordable>;
    index: number;
  }) => VNodeChild | JSX.Element;
}

export interface BasicTableProps<T = any> extends TableProps<any> {
  // 点击行选中
  clickToRowSelect?: boolean;
  isTreeTable?: boolean;


  //表格宽度
  width: string | number | undefined;
  // 自定义排序方法
  sortFn?: (sortInfo: SorterResult) => any;
  // 排序方法
  filterFn?: (data: Partial<Recordable<string[]>>) => any;
  // 取消表格的默认padding
  inset?: boolean;
  // 显示表格设置
  showTableSetting?: boolean;
  tableSetting?: TableSetting;
  // 斑马纹
  stripe?: boolean;
  // 是否自动生成key
  autoCreateKey?: boolean;
  // 计算合计行的方法
  summaryFunc?: (...arg: any) => Recordable[];
  // 自定义合计表格内容
  summaryData?: Recordable[];
  // 是否显示合计行
  showSummary?: boolean;
  // 是否可拖拽列
  canColDrag?: boolean;
  // 接口请求对象
  api?: (...arg: any) => Promise<any>;
  // 请求之前处理参数
  beforeFetch?: Fn;
  // 自定义处理接口返回参数
  afterFetch?: Fn;
  // 查询条件请求之前处理
  handleSearchInfoFn?: Fn;
  // 请求接口配置
  fetchSetting?: Partial<FetchSetting>;
  // 立即请求接口
  immediate?: boolean;
  // 在开起搜索表单的时候，如果没有数据是否显示表格
  emptyDataIsShowTable?: boolean;
  // 额外的请求参数
  searchInfo?: Recordable;
  // 默认的排序参数
  defSort?: Recordable;
  // 使用搜索表单
  useSearchForm?: boolean;
  // 表单配置
  formConfig?: Partial<FormProps>;
  // 列配置
  columns: BasicColumn<Recordable>[];
  // 是否显示序号列
  showIndexColumn?: string | number | boolean;

  // 序号列配置
  indexColumnProps?: BasicColumn<Recordable>;

  actionColumn?: BasicColumn<Recordable>;
  // 文本超过宽度是否tip显示。。。
  showOverflowTooltip?: boolean;
  // 是否继承父级高度（父级高度-表单高度-padding高度）
  isCanResizeParent?: boolean;
  // 是否可以自适应高度
  canResize?: boolean;
  // 自适应高度偏移， 计算结果-偏移量
  resizeHeightOffset?: number;

  // 在分页改变的时候清空选项
  clearSelectOnPageChange?: boolean;
  //
  rowKey?: string | ((record: Recordable) => string);
  // 数据
  dataSource?: Recordable[];
  // 标题右侧提示
  titleHelpMessage?: string | string[];
  // 表格滚动最大高度
  maxHeight?: string | number;
  // 是否显示边框
  border?: boolean;
  // 分页配置
  pagination?: PaginationProps | boolean;
  // loading加载
  loading?: boolean;

  /**
   * Row selection config
   * @type object
   */
  rowSelection?: TableRowSelection;

  /**
   * The column contains children to display
   * @default 'children'
   * @type string | string[]
   */
  childrenColumnName?: string;

  /**
   * Override default table elements
   * @type object
   */
  components?: object;

  /**
   * Expand all rows initially
   * @default false
   * @type boolean
   */
  defaultExpandAllRows?: boolean;

  /**
   * Initial expanded row keys
   * @type string[]
   */
  defaultExpandedRowKeys?: string[];

  /**
   * Current expanded row keys
   * @type string[]
   */
  expandedRowKeys?: string[];

  /**
   * Expanded container render for each row
   * @type Function
   */
  expandedRowRender?: (
    record?: ExpandedRowRenderRecord<T>
  ) => VNodeChild | JSX.Element;

  /**
   * Customize row expand Icon.
   * @type Function | VNodeChild
   */
  expandIcon?: Function | VNodeChild | JSX.Element;

  /**
   * Whether to expand row by clicking anywhere in the whole row
   * @default false
   * @type boolean
   */
  expandRowByClick?: boolean;

  /**
   * The index of `expandIcon` which column will be inserted when `expandIconAsCell` is false. default 0
   */
  expandIconColumnIndex?: number;

  /**
   * Table footer renderer
   * @type Function | VNodeChild
   */
  footer?: Function | VNodeChild | JSX.Element;

  /**
   * Indent size in pixels of tree data
   * @default 15
   * @type number
   */
  indentSize?: number;

  /**
   * i18n text including filter, sort, empty text, etc
   * @default { filterConfirm: 'Ok', filterReset: 'Reset', emptyText: 'No Data' }
   * @type object
   */
  locale?: object;

  /**
   * Row's className
   * @type Function
   */
  rowClassName?: ((data: TableCustomRecord<T>) => string) | string;

  /**
   * Set horizontal or vertical scrolling, can also be used to specify the width and height of the scroll area.
   * It is recommended to set a number for x, if you want to set it to true,
   * you need to add style .ant-table td { white-space: nowrap; }.
   * @type object
   */
  scroll?: { x?: number | true; y?: number };

  /**
   * Whether to show table header
   * @default true
   * @type boolean
   */
  showHeader?: boolean;

  /**
   * Size of table
   * @default 'default'
   * @type string
   */
  size?: string;

  /**
   * Table title renderer
   * @type Function | ScopedSlot
   */
  title?: VNodeChild | JSX.Element | string | ((data: Recordable) => string);

  /**
   * Set props on per header row
   * @type Function
   */
  customHeaderRow?: (
    column: ColumnProps<Recordable[]>,
    index: number
  ) => object;

  /**
   * Set props on per row
   * @type Function
   */
  customRow?: (record: T, index: number) => object;

  /**
   * the render container of dropdowns in table
   * @param triggerNode
   * @version 1.5.0
   */
  getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;

  /**
   * Data can be changed again before rendering.
   * The default configuration of general user empty data.
   * You can configured globally through [ConfigProvider](https://antdv.com/components/config-provider-cn/)
   *
   * @version 1.5.4
   */
  transformCellText?: Function;

  /**
   * Callback executed before editable cell submit value, not for row-editor
   *
   * The cell will not submit data while callback return false
   */
  beforeEditSubmit?: (data: {
    record: Recordable;
    index: number;
    key: string | number;
    value: any;
  }) => Promise<any>;

  /**
   * Callback executed when pagination, filters or sorter is changed
   * @param pagination
   * @param filters
   * @param sorter
   * @param currentDataSource
   */
  onChange?: (pagination: any, filters: any, sorter: any, extra: any) => void;

  /**
   * Callback executed when the row expand icon is clicked
   *
   * @param expanded
   * @param record
   */
  onExpand?: (expande: boolean, record: T) => void;

  /**
   * Callback executed when the expanded rows change
   * @param expandedRows
   */
  onExpandedRowsChange?: (expandedRows: string[] | number[]) => void;

  onColumnsChange?: (data: ColumnChangeParam[]) => void;
}

export interface GetColumnsParams {
  // 忽略索引列
  ignoreIndex?: boolean;
  // 忽略操作列
  ignoreAction?: boolean;
  sort?: boolean;
}

export interface TableActionType {
  setProps: (props: Partial<BasicTableProps>) => void;
  emit?: EmitType;
  scrollTo?: (pos: string) => void; // pos: id | "top" | "bottom"
  reload: (opt?: FetchParams) => Promise<void>;
  getColumns: (opt?: GetColumnsParams) => BasicColumn<any>[];
  setColumns: (columns: BasicColumn<any>[] | string[]) => void;
  getCacheColumns: () => BasicColumn<Recordable>[];
  getRowSelection: () => TableRowSelection<Recordable>;
  setLoading: (loading: boolean) => void;
  getDataSource: <T = Recordable>() => T[];
  updateTableDataRecord: (
    rowKey: string | number,
    record: Recordable
  ) => Recordable | void;
  deleteTableDataRecord: (rowKey: string | number) => void;
  // 分页参数引用
  getPaginationRef: () => PaginationProps | boolean;
  setPagination: (info: Partial<PaginationProps>) => void;
}

export interface ExpandedRowRenderRecord<T> extends TableCustomRecord<T> {
  indent?: number;
  expanded?: boolean;
}
export interface TableCustomRecord<T> {
  row?: T;
  rowIndex?: number;
}

export type ColumnChangeParam = {
  id: string;
  fixed: boolean | string | undefined;
  visible: boolean;
};

export interface TableRowSelection<T = any> {
  /**
   * 单选还是多选
   */

  type?: "checkbox" | "radio";
  /**
   * 选择row keys
   */
  selectedRowKeys?: string[] | number[];
  /**
   * Callback executed when selected rows change
   * @type Function
   */
  onChange?: (selectedRowKeys: string[] | number[], selectedRows?: T[]) => any;

  /**
   * Callback executed when select/deselect one row
   * @type Function
   */
  onSelect?: (
    record: T,
    selected: boolean,
    selectedRows: Object[],
    nativeEvent: Event
  ) => any;

  /**
   * Callback executed when select/deselect all rows
   * @type Function
   */
  onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => any;

  /**
   * Callback executed when row selection is inverted
   * @type Function
   */
  onSelectInvert?: (selectedRows: string[] | number[]) => any;
}

export interface InnerHandlers {
  onColumnsChange: (data: ColumnChangeParam[]) => void;
}
